今天來整理一下利用 form 元件 將canvas的圖像上傳至網站儲存
HTML
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="icon" href="multicore_logo.ico" sizes="32x32">
<!-- keep the line below for OpenProcessing compatibility -->
<script src="https://openprocessing.org/openprocessing_sketch.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/addons/p5.sound.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="mySketch.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="d1"></div>
<button id="btn1" onclick="saveCavnas()">儲存</button>
<button id="btn2" onclick="startRecord()">開始錄影</button>
<button id="btn3" onclick="stopRercord()">停止錄影</button>
<div id="d2"></div>
<video src=""></video>
<form id="fr1" name="fr1" action="upload.php" method="post" target="ff1">
<input id="img" type="hidden" name="img"><br><br>
<input id="fname" type="hidden" name="fname"><br><br>
</form>
<iframe src="" name="ff1" id="ff1"></iframe>
<body>
style.css
html, body {
margin: 0;
padding: 0;
}
#ff1 {
border:0px;
display:none;
}
mySketch.js
let can;
function setup() {
can = createCanvas(400, 400);
can.id("can1");
can.parent("d1");
background(0);
stroke(255, 255, 0);
strokeWeight(4);
}
function draw() {
if(mouseIsPressed){
line(pmouseX, pmouseY, mouseX, mouseY);
}
}
function saveCavnas(){
let url = "upload.php";
let imgurl = can.elt.toDataURL("image/png");
let fname = "ABC.png";
let postData = { img: imgurl, fname: fname };
console.log(select("#fr1"));
select("#fname").value(fname);
select("#img").value(imgurl);
select("#fr1").elt.submit();
/*
$.post(url, postData, (data, status) => {
select("#d2").html("Data: " + data + "\nStatus: " + status);
});
*/
}
其中除了利用form的 input上傳,也可以用jQuery的 $.post 方法上傳
$.post(url, postData, (data, status) => {
select("#d2").html("Data: " + data + "\nStatus: " + status);
});
upload.php
<?php
$fname = $_POST["fname"];
$img = $_POST["img"];
$img = substr(explode(";",$img)[1], 7);
file_put_contents($fname, base64_decode($img));
echo $img;
?>
其中 substr(explode(";",$img)[1], 7); 主要是用來取出資料本體
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAYAAACAvzbMAAAAAXNSR0IArs4c6QAAIABJREFUeF7t3U3sHVX9x/EvLW5kUWtqNMZQq8QawFQI0USNSgMuTAx0Jw+mSFlpKRDjQyKIBBYqJjxUMZrS1qitroCFMdFQNIqJBimYNlGCaRsSFkaELmRli/n+b+//zj2/M3fOfOfpPL
其中 explode(";",$img)[1]
以 ";" 做為分隔符號,變成
[0] data:image/png
[1] base64,iVBORw0KGgoAAAANSUhEUg ...
再用 substr(explode(";",$img)[1], 7); 取得第7個字元以後的字串(第幾個字元,以從第0個字元算起),最後變成
iVBORw0KGgoAAAANSUhEUg ..
//-----------------------
另一個功能是 將 canvas 的繪圖錄影
mySketch.js
let can;
let videoStream;
let mediaRecorder;
let chunks = []; //-- 影片暫存片段
var video;
function setup() {
can = createCanvas(400, 400);
can.id("can1");
can.parent("d1");
background(0);
stroke(255, 255, 0);
strokeWeight(4);
video = select("video");
videoStream = can.elt.captureStream(30); //-- 取得 canvas的 captureStream,設定影格速率每秒 30 格
mediaRecorder = new MediaRecorder(videoStream); //-- 建立 MediaRecorder 影音錄製器
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data); //-- 當接收到影像資料時,放入影片暫存片段中
};
mediaRecorder.onstop = function(e) {
//-- Blob(Binary large Object)物件,用來暫存影片片段資料,並設定檔案格式及編碼
let blob = new Blob(chunks, { 'type' : 'video/webm;codecs=vp9' });
chunks = [];
const videoURL = URL.createObjectURL(blob); //-- 建立暫存影片片段路徑
video.src = videoURL; //-- 設定 video 來源路徑
video.loop(); //-- 執行循環播放
const a = document.createElement("a"); //-- 建立下載超連結
a.href = videoURL; //-- 設定超連結路徑
a.download = "recording.webm"; //-- 下載檔案名稱
a.click(); //-- 執行點擊動作
//URL.revokeObjectURL(videoURL); //-- 釋放暫存影片片段路徑
//-- 利用FileReader以base64的格式,讀取blob的資料
let reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
base64data = reader.result;
console.log(base64data);
let urlv = "upload_video.php";
let fnamev = "ABC.webm";
let postDatav = { videox: base64data, fname: fnamev };
//-- 將錄影影片上傳至網站
$.post(urlv, postDatav, (data, status) => {
select("#d2").html("Data: " + data + "\nStatus: " + status);
});
}
};
}
function draw() {
if(mouseIsPressed){
line(pmouseX, pmouseY, mouseX, mouseY);
}
}
function startRecord(){
mediaRecorder.start();
console.log("start recording...");
}
function stopRercord(){
mediaRecorder.stop();
console.log("stop recording");
}
upload_video.php
<?php
$fname = $_POST["fname"];
$videox = $_POST["videox"];
$videox = substr(explode(";",$videox)[2], 7);
file_put_contents($fname, base64_decode($videox));
echo $videox;
?>
其中 substr(explode(";",$videox)[2], 7); 主要是用來取出資料本體
data:video/webm;codecs=vp9;base64,GkXfo59ChoEBQveBAULygQRC84EIQoKEd2VibUKHgQRChYECGFOAZwH/////////FUmpZpkq17GDD0JATYCGQ2hyb21lV0GGQ2hyb21lFlSua6uuqdeBAXPFh0Qk/Y6RUUmDgQFV7oEBhoVWX1ZQOOCMsIIBkLqCAZBTwIEBH0O2dQH/////////54EAoEJqoUEvgQAAAJAjAJ0BKpA
其中 explode(";",$videox)[2]
以 ";" 做為分隔符號,變成
[0] data:video/webm
[1] codecs=vp9
[2] base64,GkXfo59ChoEBQveBAULyg ...
再用 substr(explode(";",$videox)[2], 7); 取得第7個字元以後的字串(第幾個字元,以從第0個字元算起),最後變成
GkXfo59ChoEBQveBAULyg ...
//------------- 補充 ----------
如果遇到上傳時,檔案太大被擋下來的話,可以修改可上傳檔案大小的設定
1. 查詢php.ini的所在目錄
打開終端機,輸入 php --ini
得到回傳內容
Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.1
Loaded Configuration File: /opt/homebrew/etc/php/8.1/php.ini
Scan for additional .ini files in: /opt/homebrew/etc/php/8.1/conf.d
Additional .ini files parsed: /opt/homebrew/etc/php/8.1/conf.d/ext-opcache.ini
2. 打開Finder > 前往 > 前往檔案夾...
輸入 /opt/homebrew/etc/php/8.1
3. 開啟 sublime,將 php.ini 拖拉至sublime中
4. 修改以下2個參數設定後儲存
post_max_size = 1024M (預設值是8M)
upload_max_filesize = 1024M (預設值是2M)
//-----------------------
另外上傳檔案及資料的方式,經測試結果,
建議主要還是用 form 的 input 及 $.post() 的方式比較穩定
p5.js 的 httpPost() 及 JS 的 XMLHttpRequest()
都會出現接收不到上傳資料的問題,或是無法儲存檔案,或是有儲存檔案但是檔案打不開的問題
//------ 利用超連結下載錄製的影片檔 ------------
let chunks = []; //-- 影片暫存片段
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data); //-- 當接收到影像資料時,放入影片暫存片段中
};
//-- Blob(Binary large Object)物件,用來暫存影片片段資料,並設定檔案格式及編碼
let blob = new Blob(chunks, { 'type' : 'video/webm;codecs=vp9,opus' });
const videoURL = URL.createObjectURL(blob); //-- 建立暫存影片片段路徑
const a = document.createElement("a"); //-- 建立下載超連結
a.href = videoURL; //-- 設定超連結路徑
a.download = "recording.webm"; //-- 下載檔案名稱
a.click(); //-- 執行點擊動作
相關發文
D38_FileUpload 檔案上傳及縮圖處理的操作
https://ithelp.ithome.com.tw/articles/10310098